package cn.ex.ymcc.service.impl;

import cn.ex.ymcc.domain.CourseType;
import cn.ex.ymcc.mapper.CourseTypeMapper;
import cn.ex.ymcc.result.JSONResult;
import cn.ex.ymcc.service.ICourseTypeService;
import cn.ex.ymcc.util.AssertUtil;
import cn.ex.ymcc.vo.CourseTypeCrumbsVo;
import cn.ex.ymcc.vo.CourseTypeTreeDTO;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author aze
 * @since 2022-07-25
 */
@Service
@Slf4j
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    /**
     * 由于我们的课程类型树,很多地方都要用,为了保证高可用行和能抗住高并发
     *  我们需要考虑将高并发访问的数据做缓存
     *  我们使用redis来解决分布式的缓存问题
     * */
    @Override
    @Cacheable(cacheNames="coursetype", key = "'tree'")//coursetype::tree
    public List<CourseTypeTreeDTO> treeData() {
        log.info("走mysql查询");
        //3.如果有直接返回
        return treeQuery();
    }

    /**
     * 面包屑
     * @param courseTypeId
     * @return
     */
    @Override
    public List<CourseTypeCrumbsVo> courseTypeIdCrumbs(Long courseTypeId) {
        //* 1.校验参数
        AssertUtil.isNotNull(courseTypeId,"无效的ID" );
        //* 2.根据当前课程分类ID查询课程分类
        CourseType currentCourseType = super.selectById(courseTypeId);

        //* 3.得到课程分类的path ->  1037.1039.1040
        String path = currentCourseType.getPath();

        //* 4.通过“ .” 分割path,得到多个分类的id集合，而且是上上级，上级，当前级的顺序 [1037  , 1039 , 1040]
        String[] idsStr = path.split("\\.");

        //* 5.批量查询出多个分类对象  [courseType  , courseType , courseType]
        List<CourseType> courseTypes = super.selectBatchIds(Arrays.asList(idsStr));

        //* 6.需要把   [courseType  , courseType , courseType] 变成
        //*           [CourseTypeCrumbsVo ，CourseTypeCrumbsVo ，CourseTypeCrumbsVo]

        //结果
        List<CourseTypeCrumbsVo> result = new ArrayList<>(courseTypes.size());

        courseTypes.forEach(courseType ->{
            //循环分类，每次循环 ，创建一个vo对象，
            CourseTypeCrumbsVo vo = new CourseTypeCrumbsVo();

            //*   把当前分类装到 vo.ownerCourseType
            vo.setOwnerCourseType(courseType);

            //*   为当前分类查询同级分类列表，装到vo.otherCourseTypes

            Wrapper<CourseType> wrapper = new EntityWrapper<>();
            wrapper.eq("pid", courseType.getPid());

            List<CourseType> others = baseMapper.selectList(wrapper);
            //删除本身存在的，保留其他的
            others.remove(courseType);

            vo.setOtherCourseTypes(others);
            //添加到结果集
            result.add(vo);
        });

        return result;
    }

    //备份
    private JSONResult treeData1() {
        String key = "courseTypeTree";
        //1.请求过来,优先查询redis
        Object treeTmp = redisTemplate.opsForValue().get(key);
        log.info("查询redis");
        //2.如果没有,查询数据库,存入redis,再返回
        if(treeTmp == null){
            log.info("查询数据库");
            treeTmp = treeQuery();
            redisTemplate.opsForValue().set(key,treeTmp);
        }
        //3.如果有直接返回
        return JSONResult.success(treeTmp);
    }

    /**
     * 获取课程无限级树的方法
     * @return
     */
    private List<CourseTypeTreeDTO> treeQuery() {

        //到数据库中查询所有的数据
        List<CourseType> courseTypes = selectList(null);

        //用来放所有CourseType转成CourseTypeTreeDTO的集合
        List<CourseTypeTreeDTO> allDtoList = new ArrayList<>();

        //返回的数据的集合(就是每个顶级)
        List<CourseTypeTreeDTO> resultList = new ArrayList<>();

        //用来更方便得找父类  key放id   value  放dto对象
        Map<Long, CourseTypeTreeDTO> treeMap = new HashMap<>();

        courseTypes.stream().forEach(courseType -> {
            CourseTypeTreeDTO courseTypeTreeDTO = new CourseTypeTreeDTO();
            BeanUtils.copyProperties(courseType, courseTypeTreeDTO);
            courseTypeTreeDTO.setChildren(new ArrayList<>());
            courseTypeTreeDTO.setLabel(courseTypeTreeDTO.getName());
            treeMap.put(courseTypeTreeDTO.getId(), courseTypeTreeDTO);
            allDtoList.add(courseTypeTreeDTO);

        });

        //循环所有的数据  通过pid  到map中找到父
        for (CourseTypeTreeDTO dto : allDtoList) {
            //找到父
            Long pid = dto.getPid();
            CourseTypeTreeDTO courseTypeTreeDTO = treeMap.get(pid);

            //如果是null  那么说明是顶级父类
            if (courseTypeTreeDTO== null) {
                //顶级父类放到resultList
                resultList.add(dto);
                continue;
            }
            //拿到装到父类中去
            courseTypeTreeDTO.getChildren().add(dto);
        }
        return resultList;
    }
}
